// SPDX-License-Identifier: MIT
// Copyright 2020 NXP

/**
 * @file custom.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include <stdio.h>
#include "lvgl.h"
#include "custom.h"
#include <vector>
#include <string>

#define LOCK() bsp_display_lock(portMAX_DELAY)
#define UNLOCK() bsp_display_unlock()

using namespace std;

static const char *TAG = "DART_COM";

/**********************
 *      TYPEDEFS
 **********************/

#define RETRY_NUM 15
// espnow cfg
espnow_config_t espnow_config = {
    .pmk = "ESP_NOW",
    .forward_enable = 1,
    .forward_switch_channel = 0,
    .sec_enable = 0,
    .reserved1 = 0,
    .qsize = 64,
    .send_retry_num = RETRY_NUM,
    .send_max_timeout = ((TickType_t)(((TickType_t)(3000) * (TickType_t)1000) / (TickType_t)1000U)),
    .receive_enable = {
        .ack = 1,
        .forward = 1,
        .group = 1,
        .provisoning = 0,
        .control_bind = 0,
        .control_data = 0,
        .ota_status = 0,
        .ota_data = 0,
        .debug_log = 0,
        .debug_command = 0,
        .data = 1,
        .sec_status = 0,
        .sec = 0,
        .sec_data = 0,
        .reserved2 = 0,
    },
};

/*********************
 *      DEFINES
 *********************/
#define LED_PIN GPIO_NUM_2
#define KEY_PIN GPIO_NUM_9
#define DEFINE_OM_VARIABLES(T, NAME)                \
    Message::Subscriber<T> *NAME##_s1;              \
    om_topic_t *NAME##_p;                           \
    om_com_t NAME##_r;                              \
    om_status_t NAME##_s1f(om_msg_t *msg, T *data); \
    T NAME##_t;                                     \
    OM_COM_TYPE(T)                                  \
    NAME##_b;

// om_suber_t *NAME##_s1;

#define DEFINE_OM_RECV_CB(T, NAME)                                                                                           \
    om_status_t NAME##_s1f(om_msg_t *msg, T *DATA)                                                                           \
    {                                                                                                                        \
        ESP_LOGE("DART_COM", "[[IN " #NAME "_s1f");                                                                          \
        T *recvDATA = (T *)(msg->buff);                                                                                      \
        T recvData = *recvDATA;                                                                                              \
        memcpy(responseOperationData_t.stdMsg.destMAC, recvData.stdMsg.selfMAC, sizeof(recvData.stdMsg.selfMAC));            \
        memcpy(responseStatusData_t.stdMsg.destMAC, recvData.stdMsg.selfMAC, sizeof(recvData.stdMsg.selfMAC));               \
        ESP_ERROR_CHECK(esp_event_post_to(dart_events_loop_handle, Dart_Events, NAME, &recvData, sizeof(T), portMAX_DELAY)); \
        currentState = ACTIVATED;                                                                                            \
        ESP_LOGI("DART_COM", "ACTIVATED");                                                                                   \
        ESP_LOGE("DART_COM", "IN " #NAME "_s1f]]");                                                                          \
        return OM_OK;                                                                                                        \
    }
DEFINE_OM_VARIABLES(requestPing_t, requestPingData);
DEFINE_OM_VARIABLES(requestOperation_t, requestOperationData);
DEFINE_OM_VARIABLES(responseStatus_t, responseStatusData);
DEFINE_OM_VARIABLES(responseOperation_t, responseOperationData);

template <typename T>
__attribute__((packed)) struct dartCOMBuff_t
{
    uint8_t prefix;
    uint32_t topic_name_crc32;
    uint32_t data_len : 24;
    uint8_t pack_header_crc8;
    uint8_t data[sizeof(T)];
    uint8_t pack_crc8;
};

/**********************
 *  STATIC PROTOTYPES
 **********************/

/**********************
 *  STATIC VARIABLES
 **********************/
Message::Subscriber<msgBox_msg_t> *_msgbox = nullptr;
Message::Topic<msgBox_msg_t>::Queue<10> *_msgboxQueue = nullptr;
Message::Topic<msgBox_msg_t> *_msgboxTopic = nullptr;
QueueHandle_t _dartCOMPackQueue = nullptr;
msgBox_msg_t msgbox_msg;
bool msgbox_showing = false;
// msgbox维护
lv_timer_t *msgbox_timer;

void _timer_cb(lv_timer_t *timer)
{
    // ui_anim
    // Animation for moving the message box to the center of the screen
    if (msgbox_showing)
        ui_move_animation(guider_ui.Main_msgbox, 200, 0, 840, 300, &lv_anim_path_ease_in, 0, 0, 0, 0, NULL, _animation_remove_ready_cb, NULL);
}

// timer cb
void _animation_remove_ready_cb(lv_anim_t *a)
{
    LOCK();
    // if not empty, show the next msgbox
    if (_msgboxQueue->Size() > 0)
    {
        _msgboxQueue->Read(msgbox_msg);
        lv_label_set_text(lv_msgbox_get_title(guider_ui.Main_msgbox), msgbox_msg.title);
        lv_label_set_text(lv_msgbox_get_text(guider_ui.Main_msgbox), msgbox_msg.msg);
        // emerg
        switch (msgbox_msg.emerg)
        {
        case MSG_EMERG_INFO:
            lv_obj_set_style_bg_color(guider_ui.Main_msgbox, lv_color_hex(0x002140), LV_PART_MAIN | LV_STATE_DEFAULT);
            break;
        case MSG_EMERG_WARN:
            lv_obj_set_style_bg_color(guider_ui.Main_msgbox, lv_color_hex(0xB66D1B), LV_PART_MAIN | LV_STATE_DEFAULT);
            break;
        case MSG_EMERG_ERROR:
            lv_obj_set_style_bg_color(guider_ui.Main_msgbox, lv_color_hex(0x861078), LV_PART_MAIN | LV_STATE_DEFAULT);
            break;
        case MSG_EMERG_CRITICAL:
            lv_obj_set_style_bg_color(guider_ui.Main_msgbox, lv_color_hex(0x8B0015), LV_PART_MAIN | LV_STATE_DEFAULT);
            break;
        default:
            break;
        }

        msgbox_timer = lv_timer_create(_timer_cb, 1500, NULL);
        lv_timer_set_repeat_count(msgbox_timer, 1);
        // Animation for moving the message box to the center of the screen
        ui_move_animation(guider_ui.Main_msgbox, 200, 0, 330, 300, &lv_anim_path_ease_in, 0, 0, 0, 0, NULL, NULL, NULL);

        // _msgboxQueue->Pop();
    }
    else if (_msgboxQueue->Size() == 0)
    {
        lv_obj_add_flag(guider_ui.Main_msgbox, LV_OBJ_FLAG_HIDDEN);
        msgbox_showing = false;
    }
    UNLOCK();
}

void _msgbox_callback(msgBox_msg_t &msg, void *arg)
{
    LOCK();
    // 展示msgbox， 1.5s后自动关闭
    if (!msgbox_showing)
    {
        msgbox_showing = true;
        _msgboxQueue->Read(msgbox_msg);

        lv_label_set_text(lv_msgbox_get_title(guider_ui.Main_msgbox), msgbox_msg.title);
        lv_label_set_text(lv_msgbox_get_text(guider_ui.Main_msgbox), msgbox_msg.msg);
        // emerg
        switch (msgbox_msg.emerg)
        {
        case MSG_EMERG_INFO:
            lv_obj_set_style_bg_color(guider_ui.Main_msgbox, lv_color_hex(0x002140), LV_PART_MAIN | LV_STATE_DEFAULT);
            break;
        case MSG_EMERG_WARN:
            lv_obj_set_style_bg_color(guider_ui.Main_msgbox, lv_color_hex(0x967000), LV_PART_MAIN | LV_STATE_DEFAULT);
            break;
        case MSG_EMERG_ERROR:
            lv_obj_set_style_bg_color(guider_ui.Main_msgbox, lv_color_hex(0x861078), LV_PART_MAIN | LV_STATE_DEFAULT);
            break;
        case MSG_EMERG_CRITICAL:
            lv_obj_set_style_bg_color(guider_ui.Main_msgbox, lv_color_hex(0x8B0015), LV_PART_MAIN | LV_STATE_DEFAULT);
            break;
        default:
            break;
        }
        lv_obj_clear_flag(guider_ui.Main_msgbox, LV_OBJ_FLAG_HIDDEN);
        // 定时器
        msgbox_timer = lv_timer_create(_timer_cb, 1500, NULL);
        lv_timer_set_repeat_count(msgbox_timer, 1);
        // Animation for moving the message box to the center of the screen
        ui_move_animation(guider_ui.Main_msgbox, 200, 0, 330, 300, &lv_anim_path_ease_in, 0, 0, 0, 0, NULL, NULL, NULL);
        // _msgboxQueue->Pop();
    }
    UNLOCK();
    vTaskDelete(NULL);
}

template <typename T>
void dartTopicSend(om_topic_t *topic, T *data)
{
    ESP_LOGE("DART_COM", "[[IN TOPIC SEND %s", topic->name);
    esp_err_t ret = ESP_OK;
    ESP_LOG_BUFFER_HEX_LEVEL("DART_COM", data, sizeof(T), ESP_LOG_DEBUG);
    om_publish(topic, data, sizeof(T), 1, 0);
    dartCOMPack_t dataCOM;
    dataCOM.data = malloc(sizeof(dartCOMBuff_t<T>));
    // stdMsg from T* data
    memcpy(dataCOM.stdMsg.destMAC, data->stdMsg.destMAC, sizeof(data->stdMsg.destMAC));
    memcpy(dataCOM.stdMsg.selfMAC, data->stdMsg.selfMAC, sizeof(data->stdMsg.selfMAC));

    // Send
    om_com_generate_pack(topic, dataCOM.data);
    dataCOM.size = sizeof(dartCOMBuff_t<T>);
    strcpy(dataCOM.topic, topic->name);
    xQueueSend(_dartCOMPackQueue, &dataCOM, portMAX_DELAY);

    ESP_LOGE("DART_COM", "IN TOPIC SEND]]");
}

void _daemonESPNOW(void *arg)
{
    // Init
    ESP_LOGI("DART_COM", "Daemon ESPNOW Start");
    // Send Queue Preparation
    _dartCOMPackQueue = xQueueCreate(10, sizeof(dartCOMPack_t)); // Pointer Queue
    assert(_dartCOMPackQueue != NULL);

    Message::Topic<requestPing_t> requestPingDataTopic(om_find_topic("requestPingData_p", 0));
    Message::Topic<requestOperation_t> requestOperationDataTopic(om_find_topic("requestOperationData_p", 0));

    // Dart Topic Subscriber
    Message::Topic<requestPing_t>::Queue<10> requestPingDataQueue(requestPingData_p);
    Message::Topic<requestOperation_t>::Queue<10> requestOperationDataQueue(requestOperationData_p);

    espnow_frame_head_t frame_head = {
        .broadcast = true,
        .ack = 0,
        .retransmit_count = 1,
    };
    esp_err_t ret;
    dartCOMPack_t data;
    uint8_t timeDivision = 0;

    for (;;)
    {
        // Wait for the data from the queue
        if (xQueueReceive(_dartCOMPackQueue, &data, 100 / portTICK_PERIOD_MS) != pdTRUE)
        {
            timeDivision++;
            if (timeDivision == 50)
            {
                // requestPingData Pack
                requestPingData_t.connectedDevice = {0};
                // stdMsg
                dartTopicSend<>(requestPingData_p, &requestPingData_t);
                timeDivision = 0;
            }
            continue;
        }

        ESP_LOGI("DART_COM", "Topic: %s", data.topic);
        if (memcmp(data.stdMsg.destMAC, ESPNOW_ADDR_BROADCAST, 6) == 0)
        {
            frame_head.broadcast = 1;
            frame_head.ack = 0;
            frame_head.retransmit_count = RETRY_NUM;
            if (strcmp(data.topic, "requestPingData_p") == 0)
            {
                frame_head.retransmit_count = 3;
            }
        }
        else
        {
            frame_head.broadcast = 0;
            frame_head.ack = 1;
            frame_head.retransmit_count = 3;
        }
        ret = espnow_send(ESPNOW_DATA_TYPE_DATA, data.stdMsg.destMAC, data.data, data.size, &frame_head, portMAX_DELAY);

        if (ret != ESP_OK)
            _send_msg("错误", esp_err_to_name(ret), MSG_EMERG_ERROR);
        else if (strcmp(data.topic, "requestOperationData_p") == 0)
            _send_msg("提示", "命令已发送", MSG_EMERG_INFO);
        ESP_ERROR_CONTINUE(ret != ESP_OK, "<%s> espnow_send", esp_err_to_name(ret));
        ESP_LOGI("DART_COM", "<%s> <%s>: [" MACSTR "], <%s>: [" MACSTR "]\n[%d]", esp_err_to_name(ret), "selfMAC", MAC2STR(data.stdMsg.selfMAC), "destMAC", MAC2STR(data.stdMsg.destMAC), sizeof(data));
        free(data.data);
    }
    vTaskDelete(NULL);
}

esp_err_t dartEspnowRecvCB(uint8_t *src_addr, void *data, size_t size, wifi_pkt_rx_ctrl_t *rx_ctrl)
{
    ESP_LOGI(TAG, "[[IN RECV_CB");
    ESP_PARAM_CHECK(src_addr);
    ESP_PARAM_CHECK(data);
    ESP_PARAM_CHECK(size);
    ESP_PARAM_CHECK(rx_ctrl);
    // peer list add
    if (espnow_add_peer(src_addr, NULL) != ESP_OK)
    {
        ESP_LOGE(TAG, "Add peer failed");
    }
    // om_com_prase_recv(&requestPingData_r, (uint8_t *)data, size, true, false);
    // om_com_prase_recv(&requestOperationData_r, (uint8_t *)data, size, true, false);
    om_com_prase_recv(&responseOperationData_r, (uint8_t *)data, size, true, false);
    om_com_prase_recv(&responseStatusData_r, (uint8_t *)data, size, true, false);
    ESP_LOGI(TAG, "IN RECV_CB]]");
    return ESP_OK;
}

void _send_msg(const char *title, const char *msg, msg_emerg_t emerg)
{
    // Construct a message
    msgBox_msg_t msgbox_msg;
    strcpy(msgbox_msg.title, title);
    strcpy(msgbox_msg.msg, msg);
    msgbox_msg.emerg = emerg;
    // Publish the message
    _msgboxTopic->Publish(msgbox_msg);
}

bool _send_msg_topic_cb(msgBox_msg_t &msg, void *arg)
{
    // Send a message
    ESP_LOGI("MSGBOX", "Title: %s, Msg: %s, Emerg: %d", msg.title, msg.msg, msg.emerg);
    if (!msgbox_showing)
        xTaskCreate((TaskFunction_t)_msgbox_callback, "msgbox_callback", 2048, &msg, 6, NULL);
    return true;
}

std::vector<responseStatus_t> dart_status_v_;
typedef struct known_devices_t
{
    uint8_t mac[6];
    TickType_t last_contact;
};

std::vector<known_devices_t> known_devices;

bool dartStatusCallback(responseStatus_t &msg, void *arg)
{
    ESP_LOGI("DART_COM", "Status Callback");
    // char info[30];
    // snprintf(info, 30, "%.2fV, %d%%, %d, %d, %.2f, %.2f", msg.batteryVoltage / 1000.0, msg.batteryLevel, msg.boostState, msg.chargeState, msg.chargeCurrent / 1000, msg.chargeVoltage / 1000);
    // _send_msg("提示", info, MSG_EMERG_INFO);
    // 不在known_devices里的加入known_devices，超时没有连接的则删除；将消息按照压入dart_status_v_，同一个mac只允许一个；然后打印进入“异常信息速览”
    // Check if the device is in the known_devices and if it is disconnected
    bool known = false;
    for (size_t i = 0; i < known_devices.size(); i++)
    {
        if (memcmp(known_devices[i].mac, msg.stdMsg.selfMAC, 6) == 0)
        {
            known = true;
            known_devices[i].last_contact = xTaskGetTickCount();
            dart_status_v_[i] = msg;
        }
        if (xTaskGetTickCount() - known_devices[i].last_contact > 10000)
        {
            known_devices.erase(known_devices.begin() + i);
            dart_status_v_.erase(dart_status_v_.begin() + i);
        }
    }
    if (!known)
    {
        known_devices_t new_device;
        memcpy(new_device.mac, msg.stdMsg.selfMAC, 6);
        new_device.last_contact = xTaskGetTickCount();
        known_devices.push_back(new_device);
        dart_status_v_.push_back(msg);
    }

    //  Print the abnormal information to the screen
    char abnormal_info[1000];
    string abnormal_info_str;
    for (auto i : dart_status_v_)
    {
        if (i.chargeState)
        {
            snprintf(abnormal_info, 1000, MACSTR " %.2f V %d%%, Charge: %.1f A,  %.1f V\n", MAC2STR(i.stdMsg.selfMAC), i.batteryVoltage / 1000.0, i.batteryLevel, i.chargeCurrent / 1000.0, i.chargeVoltage / 1000.0);
        }
        else
        {
            snprintf(abnormal_info, 1000, MACSTR " %.2f V %d%%, Power: %s\n", MAC2STR(i.stdMsg.selfMAC),
                     i.batteryVoltage / 1000.0, i.batteryLevel, i.boostState ? "ON" : "OFF");
        }
        abnormal_info_str += abnormal_info;
    }
    lv_label_set_text(guider_ui.Main_labelWarnings, abnormal_info_str.c_str());
    // Update the status
    ESP_LOGI("DART_COM", "Battery Voltage: %d, Battery Level: %d, Boost State: %d, Charge State: %d, Charge Current: %.2f, Charge Voltage: %.2f", msg.batteryVoltage, msg.batteryLevel, msg.boostState, msg.chargeState, msg.chargeCurrent / 1000.0, msg.chargeVoltage / 1000.0);
    return true;
}

// 按键回调函数
void btnAllOn_cb(lv_event_t *e)
{
    // Write codes btnAllOn
    // Send requestOperation
    requestOperation_t requestOperation;
    memcpy(requestOperation.stdMsg.destMAC, requestOperationData_t.stdMsg.destMAC, sizeof(requestOperationData_t.stdMsg.destMAC));
    memcpy(requestOperation.stdMsg.selfMAC, requestOperationData_t.stdMsg.selfMAC, sizeof(requestOperationData_t.stdMsg.selfMAC));
    requestOperation.operation = OPERATION_PWR;
    requestOperation.operationParam = PWR_ON;
    dartTopicSend<>(requestOperationData_p, &requestOperation);
}

void btnAllOff_cb(lv_event_t *e)
{
    // Write codes btnAllOff
    // Send requestOperation
    requestOperation_t requestOperation;
    memcpy(requestOperation.stdMsg.destMAC, requestOperationData_t.stdMsg.destMAC, sizeof(requestOperationData_t.stdMsg.destMAC));
    memcpy(requestOperation.stdMsg.selfMAC, requestOperationData_t.stdMsg.selfMAC, sizeof(requestOperationData_t.stdMsg.selfMAC));
    requestOperation.operation = OPERATION_PWR;
    requestOperation.operationParam = PWR_OFF;
    dartTopicSend<>(requestOperationData_p, &requestOperation);
}

void swPDEnable_cb(lv_event_t *e)
{
    // Write codes swPDEnable
    if (lv_obj_has_state(guider_ui.Main_swPDEnable, LV_STATE_CHECKED))
    {
        _send_msg("提示", "无线充电已打开", MSG_EMERG_INFO);
        gpio_set_level(GPIO_NUM_15, 1);
        setFanSpeedPercentage(3);
    }
    else
    {
        _send_msg("提示", "无线充电已关闭", MSG_EMERG_INFO);
        gpio_set_level(GPIO_NUM_15, 0);
    }
}

void printLogWithProgress(const char *label, int progress)
{
    ESP_LOGI("DART_INIT", "[%d] %s", progress, label);
    LOCK();
    lv_label_set_text(guider_ui.Init_labelInitLog, label);
    lv_bar_set_value(guider_ui.Init_bar_1, progress, LV_ANIM_ON);
    UNLOCK();
}

void dartChargerAppSetup(lv_ui *ui)
{
    /* Add your codes here */
    // *****Screen: Init*****
    char initLogText[50];
    int progress = 0;
    strcpy(initLogText, "Initializing NVS Flash and Communication...");
    printLogWithProgress(initLogText, progress);
    vTaskDelay(100);
    LOCK();
    static Firmware fw(0);
    firmware = &fw;
    // ESP-NOW Init
    ESP_ERROR_CHECK(espnow_init(&espnow_config));
    ESP_ERROR_CHECK(espnow_set_config_for_data_type(ESPNOW_DATA_TYPE_DATA, true, dartEspnowRecvCB));
    // OneMessage Topic Subscribe
    Message message;
    static Message::Topic<msgBox_msg_t> msgboxTopic("msgbox", true);
    static Message::Subscriber<msgBox_msg_t> msgbox(msgboxTopic);
    static Message::Topic<msgBox_msg_t>::Queue<10> msgboxQueue(msgboxTopic.om_topic_);

    // Topic for UI Message
    _msgboxTopic = &msgboxTopic;
    _msgboxTopic->RegisterCallback<bool(msgBox_msg_t & msg, void *arg), void *>(_send_msg_topic_cb, NULL);
    _msgbox = &msgbox;
    _msgboxQueue = &msgboxQueue;
    // Dart, using C API
    requestPingData_p = om_config_topic(NULL, "ca", "requestPingData_p", sizeof(requestPing_t));
    requestOperationData_p = om_config_topic(NULL, "ca", "requestOperationData_p", sizeof(requestOperation_t));
    responseStatusData_p = om_config_topic(NULL, "ca", "responseStatusData_p", sizeof(responseStatus_t));
    responseOperationData_p = om_config_topic(NULL, "ca", "responseOperationData_p", sizeof(responseOperation_t));

    om_com_create(&requestPingData_r, 128, 5, 128);
    om_com_create(&requestOperationData_r, 128, 5, 128);
    om_com_create(&responseStatusData_r, 128, 5, 128);
    om_com_create(&responseOperationData_r, 128, 5, 128);

    om_com_add_topic(&requestPingData_r, requestPingData_p);
    om_com_add_topic(&requestOperationData_r, requestOperationData_p);
    om_com_add_topic(&responseStatusData_r, responseStatusData_p);
    om_com_add_topic(&responseOperationData_r, responseOperationData_p);

    Message::Topic<responseStatus_t>(responseStatusData_p).RegisterCallback<bool((responseStatus_t & msg, void *arg)), void *>(dartStatusCallback, NULL);

    // MAC Address Setting
    for (int i = 0; i < 6; ++i)
    {
        requestPingData_t.stdMsg.destMAC[i] = 0xff;
        requestOperationData_t.stdMsg.destMAC[i] = 0xff;
        responseStatusData_t.stdMsg.destMAC[i] = 0xff;
        responseOperationData_t.stdMsg.destMAC[i] = 0xff;
    }
    esp_read_mac(requestPingData_t.stdMsg.selfMAC, ESP_MAC_WIFI_STA);
    esp_read_mac(requestOperationData_t.stdMsg.selfMAC, ESP_MAC_WIFI_STA);
    esp_read_mac(responseStatusData_t.stdMsg.selfMAC, ESP_MAC_WIFI_STA);
    esp_read_mac(responseOperationData_t.stdMsg.selfMAC, ESP_MAC_WIFI_STA);
    UNLOCK();
    strcpy(initLogText, "Initializing PD Controller...");
    progress = 50;
    printLogWithProgress(initLogText, progress);
    vTaskDelay(10);
    LOCK();
    // PD Controller Init
    initHUSB238();
    int trial = -1;
    // update_pd_status();
    uint8_t voltage = m_src_voltage[status.PD_SRC_VOLTAGE];
    while (voltage < 9)
    {
        vTaskDelay(100);
        voltage = get_pd_voltage();
        if (voltage >= 9)
        {
            trial = -1;
            break;
        }
        else
        {
            trial++;
            if (trial >= 20)
                break;
        }
        // // Request
        // set_voltage(PDO_20V);
    }
    vTaskDelay(10);
    UNLOCK();
    progress = 100;
    strcpy(initLogText, "Initialized");
    printLogWithProgress(initLogText, progress);

    vTaskDelay(1000); // Change Screen
    LOCK();
    ui_load_scr_animation(ui, &ui->Main, ui->Main_del, &ui->Init_del, setup_scr_Main, LV_SCR_LOAD_ANIM_NONE, 0, 0, false, true);
    lv_obj_clear_flag(guider_ui.Main, LV_OBJ_FLAG_SCROLLABLE);
    lv_obj_add_event_cb(guider_ui.Main_btnAllOn, btnAllOn_cb, LV_EVENT_CLICKED, NULL);           // 绑定回调函数
    lv_obj_add_event_cb(guider_ui.Main_btnAllOff, btnAllOff_cb, LV_EVENT_CLICKED, NULL);         // 绑定回调函数
    lv_obj_add_event_cb(guider_ui.Main_swPDEnable, swPDEnable_cb, LV_EVENT_VALUE_CHANGED, NULL); // 绑定回调函数
    lv_obj_clear_flag(guider_ui.Main_msgbox, LV_OBJ_FLAG_SCROLLABLE);

    initFan();
    if (trial == -1)
    {
        _send_msg("提示", "无线充电已打开", MSG_EMERG_INFO);
        // 开启无线充电
        gpio_set_level(GPIO_NUM_15, 1);
        setFanSpeedPercentage(10);
        // 开关设置成1
        lv_obj_add_state(guider_ui.Main_swPDEnable, LV_STATE_CHECKED);
    }
    else
    {
        char capabilityMsg[25];
        snprintf(capabilityMsg, 25, "PD电源错误(%dV)", get_pd_voltage());
        _send_msg("错误", capabilityMsg, MSG_EMERG_CRITICAL);
    }
    // InitDaemon
    initHUSB238Daemon();
    xTaskCreate(_daemonESPNOW, "daemonESPNOW", 8192, NULL, 5, NULL);
    UNLOCK();
}